# SlideTransition - Slide out old screen and slide in the new screen
# Copyright (C) 2007 Lauri Taimila
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

__licence__ = "GPLv2"
__copyright__ = "2007, Lauri Taimila"
__author__ = "Lauri Taimila <lauri@taimila.com>"

import clutter

from frontend.gui.screens.screen import Screen
from frontend.gui.transitions.transition import Transition

class SlideTransition(Transition):
    """
    SlideTransition 
    
    Slide all components from the "from_screen" away from the screen and slide 
    in all the components of the "to_screen". This class implements simple slide
    effect for screen changes.
    """
    
    def forwardEffect(self, from_screen, to_screen):   
        """ 
        Slide out all components from the "from_screen" and slide in all components
        of the "to_screen".
        """
        if to_screen.get_type() == Screen.DIALOG:
            self.forward_effect_for_dialog(from_screen, to_screen)
        else:
            width = int(self.stage.get_width())
            # Initialize to_screen for animation
            to_screen.get_group().set_position(-width, 0)
            to_screen.get_group().show()
            
            # Slide out timeline
            if from_screen is not None:
                self.slide_out = clutter.Timeline(20, 60)
                self.alpha_out = clutter.Alpha(self.slide_out, clutter.smoothstep_inc_func)
                self.out_behaviour = clutter.BehaviourPath(self.alpha_out, ((0,0),(width,0)))
                self.out_behaviour.apply(from_screen.get_group())
            
            # Slide in timeline
            self.slide_in = clutter.Timeline(20, 60)
            self.alpha_in = clutter.Alpha(self.slide_in, clutter.smoothstep_inc_func)
            self.in_behaviour = clutter.BehaviourPath(self.alpha_in, ((-width,0),(0,0)))
            self.in_behaviour.apply(to_screen.get_group())
        
            # Start transition animating
            if from_screen is not None:
                self.slide_out.start()
            self.slide_in.start()
    
    def backwardEffect(self, from_screen, to_screen):   
        """ 
        Slide out all components from the "from_screen" and slide in all components
        of the "to_screen".
        """
        if from_screen.get_type() == Screen.DIALOG:
            self.backward_effect_for_dialog(from_screen, to_screen)
        else:
            width = int(self.stage.get_width())
            # Initialize to_screen for animation
            to_screen.get_group().set_position(width, 0)
            to_screen.get_group().show()
            
            # Slide out timeline
            self.slide_out = clutter.Timeline(20, 60)
            self.alpha_out = clutter.Alpha(self.slide_out, clutter.smoothstep_inc_func)
            self.out_behaviour = clutter.BehaviourPath(self.alpha_out, ((0,0),(-width,0)))
            self.out_behaviour.apply(from_screen.get_group())
            self.slide_out.connect('completed', self._remove_from_stage_callback, from_screen)
            
            # Slide in timeline
            self.slide_in = clutter.Timeline(20, 60)
            self.alpha_in = clutter.Alpha(self.slide_in, clutter.smoothstep_inc_func)
            self.in_behaviour = clutter.BehaviourPath(self.alpha_in, ((width,0),(0,0)))
            self.in_behaviour.apply(to_screen.get_group())
            
            # Start transition animating
            self.slide_out.start()
            self.slide_in.start()            
    
    def forward_effect_for_dialog(self, from_screen, to_screen):
        """This is called when next screen is dialog."""
        #Fade current screen away
        self.slide_out = clutter.Timeline(20, 60)
        self.alpha_out = clutter.Alpha(self.slide_out, clutter.smoothstep_inc_func)
        
        self.out_behaviour = clutter.BehaviourOpacity(self.alpha_out, 254, 64)
        self.out_behaviour.apply(from_screen.get_group())
        
        self.out_behaviour2 = clutter.BehaviourScale(self.alpha_out, 1, 0.9, clutter.GRAVITY_CENTER)
        self.out_behaviour2.apply(from_screen.get_group())
        
        #Fade dialog in
        self.slide_in = clutter.Timeline(20, 60)
        self.alpha_in = clutter.Alpha(self.slide_in, clutter.smoothstep_inc_func)
        
        to_screen.get_group().set_opacity(0)
        self.in_behaviour = clutter.BehaviourOpacity(self.alpha_in, 0, 255)
        self.in_behaviour.apply(to_screen.get_group())
        
        self.in_behaviour2 = clutter.BehaviourDepth(self.alpha_in, 100, 0)
        self.in_behaviour2.apply(to_screen.get_group())
        
        # Start animations
        self.slide_out.start()
        self.slide_in.start()
        
    def backward_effect_for_dialog(self, from_screen, to_screen):
        """This is used when dialog is closed and control returns to screen."""
        #Fade current screen away
        self.slide_out = clutter.Timeline(20, 60)
        self.slide_out.connect('completed', self._remove_from_stage_callback, from_screen)
        self.alpha_out = clutter.Alpha(self.slide_out, clutter.smoothstep_inc_func)
        
        self.out_behaviour = clutter.BehaviourOpacity(self.alpha_out, 254, 0)
        self.out_behaviour.apply(from_screen.get_group())
        
        self.out_behaviour2 = clutter.BehaviourDepth(self.alpha_out, 0, 100)
        self.out_behaviour2.apply(from_screen.get_group())
        
        #Fade dialog in
        self.slide_in = clutter.Timeline(20, 60)
        self.alpha_in = clutter.Alpha(self.slide_in, clutter.smoothstep_inc_func)
        
        self.in_behaviour = clutter.BehaviourOpacity(self.alpha_in, 64, 255)
        self.in_behaviour.apply(to_screen.get_group())
        
        self.in_behaviour2 = clutter.BehaviourScale(self.alpha_in, 0.9, 1, clutter.GRAVITY_CENTER)
        self.in_behaviour2.apply(to_screen.get_group())
        
        # Start animations
        self.slide_out.start()
        self.slide_in.start()
    
    def _remove_from_stage_callback(self, timeline, screen):
        """
        Callback for fadeout timeline. This method is called when transition
        direction is BACKWARDS. This method removes old screen from stage.
        """
        self.stage.remove(screen.get_group())